home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_03_04 / 3n04017a < prev    next >
Text File  |  1992-02-18  |  14KB  |  445 lines

  1. #include <dos.h>
  2. #include "dma.h"
  3.  
  4. //--- Global Data --------------------------------------------------------
  5. BYTE PageRegister[ 8 ] = { DMA_PAGE_0, DMA_PAGE_1, DMA_PAGE_2, DMA_PAGE_3, 
  6.                            DMA_PAGE_4, DMA_PAGE_5, DMA_PAGE_6, DMA_PAGE_7 };
  7. DMA_DESCRIPTOR DmaDescriptor;
  8. DMA_INFO DmaInfo;
  9. //--- External References ------------------------------------------------
  10. extern void Device_RetrieveDmaInfo( DMA_INFO * );
  11. extern INTERRUPT_TYPE Device_TypeOfInterrupt( void );
  12. extern USHORT Device_QuerySpaceAvail( void );
  13. extern USHORT Device_QueryDataAvail( void );
  14. extern Env_DoEoi( void );
  15. //--- Local Functions ----------------------------------------------------
  16. void DmaAbort(DMA_INFO *);
  17. void DmaSendComplete( DMA_INFO * );
  18. void DmaReceiveComplete( DMA_INFO * );
  19. void DmaSend( DMA_INFO * );
  20. void DmaReceive( DMA_INFO * );
  21. void ProgramDmaController( DMA_INFO * );
  22. USHORT ReadTransferCount( DMA_INFO * );
  23. void CheckForPageWrap( USHORT *pCount, ULONG physAddr );
  24. #ifdef DOS
  25. ULONG Dos_GetPhysAddr( char far *pBuffer, DMA_INFO *pDmaInfo );
  26. #endif
  27. #ifdef WIN3
  28. ULONG Win3_GetPhysAddr( char far * pBuffer, DMA_INFO *pDmaInfo );
  29. void Win3_ReleaseBuffer( DMA_INFO * );
  30. #endif
  31. #ifdef OS2
  32. ULONG OS2_GetPhysAddr( char *pBuffer, DMA_INFO *pDmaInfo, 
  33.       BUF_INFO *pBufStruc );
  34. #endif
  35.  
  36. void InterruptHandler( void )
  37. {
  38.    INTERRUPT_TYPE intType;
  39.  
  40.    /* Determine cause(s) of interrupt. */  
  41.    intType = Device_TypeOfInterrupt();
  42.  
  43.    /* Interrupt priority is:                          
  44.     * 1. DmaAbort
  45.     * 2. DmaComplete
  46.     * 3. DeviceRdyToTx
  47.     * 4. DeviceRdyToRx */
  48.    if (intType.DmaAbort)
  49.       DmaAbort( &DmaInfo );
  50.    if (intType.DmaComplete)
  51.    {
  52.       /* Interrupt type doesn't tell us whether completed 
  53.        * transfer was TO device or FROM device. Use 
  54.        * TransferType field to decide. */
  55.       if (DmaInfo.TransferType == TRANSFER_WRITE_TO_MEM )
  56.          DmaReceiveComplete( &DmaInfo );
  57.       else if (DmaInfo.TransferType == TRANSFER_READ_FROM_MEM)
  58.          DmaSendComplete( &DmaInfo );
  59.    }
  60.  
  61.   /* After DmaComplete housekeeping, driver is 
  62.    * ready to handle another DMA transfer during 
  63.    * same interrupt, if device is ready. */ 
  64.   if (intType.DeviceRdyToTx)          
  65.      DmaReceive( &DmaInfo);           
  66.   if (intType.DeviceRdyToRx)          
  67.      DmaSend( &DmaInfo);              
  68.    /* DMA stuff is complete. Must send EOI to 
  69.     * interrupt controller before returning. */
  70.    Env_DoEoi();  
  71. }
  72.  
  73. void DmaAbort( DMA_INFO *pDmaInfo )
  74. {
  75.    USHORT   bytesNotTransferred;
  76.  
  77. /* Must determine how many bytes were transferred 
  78.  * before abort. First ask DMA controller how many 
  79.  * bytes have not yet been transferred. Then 
  80.  * subtract from original transfer count. */
  81.    bytesNotTransferred = ReadTransferCount( pDmaInfo );
  82.    pDmaInfo->TransferCount = pDmaInfo->TransferCount - bytesNotTransferred;
  83.    // Now that TransferCount field is updated, 
  84.    // call subroutine to advance queue pointers.
  85.    if (pDmaInfo->TransferType == TRANSFER_WRITE_TO_MEM)
  86.       DmaReceiveComplete( pDmaInfo );
  87.    else if (pDmaInfo->TransferType == TRANSFER_READ_FROM_MEM)   
  88.       DmaSendComplete( pDmaInfo );
  89. }
  90.  
  91. void DmaReceiveComplete( DMA_INFO *pDmaInfo )
  92. {
  93.    // Update receive queue ptr, accounting for wrap.
  94.    pDmaInfo->RxBuf.pIn += pDmaInfo->TransferCount;
  95.    if (pDmaInfo->RxBuf.pIn > pDmaInfo->RxBuf.pEnd)
  96.       pDmaInfo->RxBuf.pIn = pDmaInfo->RxBuf.pStart;
  97.  
  98. #ifdef WIN3
  99.    Win3_ReleaseBuffer( pDmaInfo );
  100. #endif
  101.  
  102. }
  103.  
  104. void DmaSendComplete( DMA_INFO *pDmaInfo )
  105. {
  106.    // Update transmit queue ptr, accounting for wrap.
  107.    pDmaInfo->TxBuf.pOut += pDmaInfo->TransferCount;
  108.    if (pDmaInfo->TxBuf.pOut > pDmaInfo->TxBuf.pEnd)
  109.       pDmaInfo->TxBuf.pOut = pDmaInfo->TxBuf.pStart;
  110.  
  111. #ifdef WIN3
  112.    Win3_ReleaseBuffer( pDmaInfo );
  113. #endif
  114.  
  115. }
  116.  
  117. void DmaSend( DMA_INFO *pDmaInfo )
  118. {
  119.    char     *pIn, *pOut; 
  120.    USHORT   bytesInQueue;
  121.    USHORT   roomInDevice;
  122.  
  123.    // Calculate bytes in driver's transmit queue.        
  124.    pOut = pDmaInfo->TxBuf.pOut;
  125.    pIn = pDmaInfo->TxBuf.pIn;
  126.    if (pIn >= pOut)       
  127.    {
  128.       bytesInQueue = pIn - pOut;
  129.    }
  130.    else
  131.    {
  132.       // DMA transfer data must be contiguous, 
  133.       // so stop at end of buffer.
  134.       bytesInQueue = pDmaInfo->TxBuf.pEnd - pOut + 1;
  135.    }
  136.  
  137.    // Ask device how much space it has available 
  138.    // for new data. Device may not have enough space for 
  139.    // all we have.
  140.    roomInDevice = Dev_QuerySpaceAvail();
  141.    if (roomInDevice < bytesInQueue)
  142.       pDmaInfo->TransferCount = roomInDevice;
  143.    else
  144.       pDmaInfo->TransferCount = bytesInQueue;
  145.  
  146.    // Determine physical address of first byte in DMA 
  147.    // transfer. Since we're sending data _to_ device, 
  148.    // use the pOut pointer.
  149.    pDmaInfo->TransferPhys = 
  150.       GET_PHYS_ADDR( (char far *)pDmaInfo->TxBuf.pOut,
  151.                      pDmaInfo, &pDmaInfo->TxBuf );
  152.  
  153.    pDmaInfo->TransferType = TRANSFER_READ_FROM_MEM;      
  154.    ProgramDmaController( pDmaInfo );
  155. }
  156.  
  157. void DmaReceive( DMA_INFO *pDmaInfo )
  158. {
  159.    USHORT   spaceAvail;
  160.    USHORT   dataAvail;
  161.    char     *pOut, *pIn;
  162.  
  163.    // Calculate space in driver's receive queue.
  164.    pIn = pDmaInfo->RxBuf.pIn;
  165.    pOut = pDmaInfo->RxBuf.pOut;
  166.    if (pOut > pIn)       
  167.    {
  168.       spaceAvail = pOut - pIn - 1; 
  169.    }
  170.    else
  171.    {
  172.       // DMA transfer data must be contiguous, 
  173.       // so stop at end of buffer.
  174.       spaceAvail = pDmaInfo->RxBuf.pEnd - pIn + 1;
  175.       if (pOut == pDmaInfo->RxBuf.pStart)
  176.          spaceAvail--;  // must leave last byte empty
  177.    }
  178.    if (spaceAvail)
  179.    {
  180.       dataAvail = Dev_QueryDataAvail();
  181.       if (dataAvail > spaceAvail)   
  182.          pDmaInfo->TransferCount = spaceAvail;
  183.       else 
  184.          pDmaInfo->TransferCount = dataAvail;
  185.  
  186.       // Determine physical address of first byte in 
  187.       // DMA transfer. Since we're receiving data 
  188.       // _from_ device, use the pIn pointer.
  189.       pDmaInfo->TransferPhys = 
  190.             GET_PHYS_ADDR( (char far *)pDmaInfo->RxBuf.pIn,
  191.                            pDmaInfo, &pDmaInfo->RxBuf );
  192.       pDmaInfo->TransferType = TRANSFER_WRITE_TO_MEM;      
  193.       ProgramDmaController( pDmaInfo );
  194.    }
  195. }
  196.  
  197. USHORT ReadTransferCount( DMA_INFO *pDmaInfo )
  198. {
  199.    USHORT   count;
  200.    BYTE     regTransferCount;
  201.    BYTE     channel = pDmaInfo->Channel;  
  202.  
  203.    if (pDmaInfo->BusType != BUS_MICROCHANNEL)
  204.    {
  205.       if (channel <= 3)
  206.       {
  207.          regTransferCount = DMA_CONTROLLER_0_3 
  208.                            + DMA_OFFSET_COUNT;
  209.          outp( DMA_CONTROLLER_0_3 + DMA_OFFSET_CLEAR, 0 );
  210.       }
  211.       else
  212.       {
  213.          regTransferCount = DMA_CONTROLLER_4_7 
  214.                            + DMA_OFFSET_COUNT;
  215.          outp( DMA_CONTROLLER_4_7 + DMA_OFFSET_CLEAR, 0 );
  216.       }
  217.       regTransferCount += (channel << 1);
  218.       // First byte read is LSB of count.
  219.       count = inp( regTransferCount );    
  220.       // Second byte read is MSB of count. 
  221.       // Combine with LSB.
  222.       count = (count << 8) | (inp( regTransferCount ) ); 
  223.    }
  224.    else
  225.    {
  226.       outp( DMA_XFN, Get_Count + channel );
  227.       // First byte read is LSB of count.
  228.       count = inp( DMA_EXE );               
  229.       // Second byte read is MSB of count. 
  230.       // Combine with LSB.
  231.       count = (count >> 8) | inp( DMA_EXE );  
  232.    }  
  233.    return( count - 1 );
  234. }
  235.  
  236. void ProgramDmaController( DMA_INFO * pDmaInfo )
  237. {
  238.    ULONG    physAddr = pDmaInfo->TransferPhys;
  239.    USHORT   count = pDmaInfo->TransferCount;
  240.    BYTE     channel = pDmaInfo->Channel;
  241.    BYTE     baseReg;
  242.    BYTE     tempReg;   
  243.  
  244.    // Controller chips on MicroChannel are 
  245.    // different than XT or AT.
  246.    if (pDmaInfo->BusType != BUS_MICROCHANNEL)
  247.    {
  248.       if (channel <= 3)
  249.       {
  250.          baseReg = DMA_CONTROLLER_0_3;
  251.          outp( DMA_CONTROLLER_0_3 + DMA_OFFSET_CLEAR, 0 );
  252.       }
  253.       else
  254.       {
  255.          baseReg = DMA_CONTROLLER_4_7;
  256.          outp( DMA_CONTROLLER_4_7 + DMA_OFFSET_CLEAR, 0 );
  257.       }
  258.       // Set channel's mask bit to disable channel 
  259.       outp( baseReg + DMA_OFFSET_MASK, channel | 0x04 );
  260.       // Set mode to